package com.tcm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tcm.entity.*;
import com.tcm.entity.dto.param.TeachingUpdateParam;
import com.tcm.entity.vo.ClazzListResult;
import com.tcm.entity.vo.TeachingListResult;
import com.tcm.entity.vo.TeachingSubListResult;
import com.tcm.exception.DatabaseOperationException;
import com.tcm.exception.EntityInvalidException;
import com.tcm.mapper.TeachingMapper;
import com.tcm.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 教学管理业务实现类
 * @author Guqier
 * @version 1.0
 * @date 2023/7/13 14:50
 */
@Slf4j
@Service
public class TeachingServiceImpl extends ServiceImpl<TeachingMapper, Teaching> implements TeachingService {

    @Autowired
    private TermService termService;

    @Autowired
    private BookService bookService;

    @Autowired
    private TeacherService teacherService;

    @Autowired
    private ClazzService clazzService;

    @Autowired
    private LeaderService leaderService;

    public static final int COURSE_TYPE = 0;// 课程类型在ts_book表中为0


    /**
     * 添加教学计划
     * @param param 教学计划更新参数封装对象
     * @param currUserId 当前登录用户ID
     * @return 添加结果，true为成功
     * @throws Exception 自定义异常
     */
    @Override
    @Transactional
    public boolean addTeaching(TeachingUpdateParam param, Long currUserId) throws Exception{
        // 校验信息是否正确
        Term term = termService.getById(param.getTermId());
        Book book = bookService.getById(param.getBookId());
        Teacher teacher = teacherService.getById(param.getTeacherId());
        List<Clazz> clazzes = clazzService.getBaseMapper().selectBatchIds(param.getClazzIds());
        if (term == null || book == null || teacher == null || clazzes == null){
            throw new Exception("参数无效");
        }
        if (!book.getType().equals(COURSE_TYPE)){
            throw new Exception("课程ID错误");
        }
        // 插入教学计划
        List<Teaching> saveList = new ArrayList<>();
        for (Clazz clazz : clazzes) {
            Teaching teaching = new Teaching();
            teaching.setTermId(term.getId());
            teaching.setBookId(book.getId());
            teaching.setClazzId(clazz.getId());
            teaching.setTeacherId(teacher.getId());
            teaching.setCreateUser(currUserId);
            teaching.setUpdateUser(currUserId);
            saveList.add(teaching);
        }
        return this.saveBatch(saveList);
    }

    /**
     * 修改教学计划
     * @param param 教学计划更新数据封装对象
     * @param currUserId 当前登录用户ID
     * @return 修改结果，true为成功
     */
    @Override
    @Transactional
    public boolean modifyTeaching(TeachingUpdateParam param, Long currUserId){
        // 通过学期、课程、教师构造条件
        LambdaQueryWrapper<Teaching> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Teaching::getTermId, param.getTermId());
        queryWrapper.eq(Teaching::getBookId, param.getBookId());
        queryWrapper.eq(Teaching::getTeacherId, param.getTeacherId());
        List<Teaching> teachingList = this.list(queryWrapper);
        if (CollectionUtils.isEmpty(teachingList)) {
            throw new EntityInvalidException("教学计划不存在");
        }
        // 根据ClazzId求差集，现有-参数
        List<Long> deleteIds = teachingList.stream().filter(teaching -> !param.getClazzIds().contains(teaching.getClazzId())).map(Teaching::getId).collect(Collectors.toList());
        this.removeByIds(deleteIds);// 删除差集教学计划记录
        // 根据ClazzId求差集，参数-现有
        List<Teaching> teachingList2 = this.list(queryWrapper);
        List<Long> clazzIds = param.getClazzIds().stream().filter(c -> !teachingList2.stream().map(Teaching::getClazzId).collect(Collectors.toList()).contains(c)).collect(Collectors.toList());
        // 插入缺少的教学计划
        List<Teaching> saveList = new ArrayList<>();
        for (Long clazzId : clazzIds) {
            Teaching teaching = new Teaching();
            teaching.setTermId(param.getTermId());
            teaching.setBookId(param.getBookId());
            teaching.setClazzId(clazzId);
            teaching.setTeacherId(param.getTeacherId());
            teaching.setCreateUser(currUserId);
            teaching.setUpdateUser(currUserId);
            saveList.add(teaching);
        }
        return this.saveBatch(saveList);
    }

    /**
     * 删除教学计划
     * @param termId 学期ID
     * @param bookId 课程ID
     * @param teacherId 教师ID
     * @param currUserId 当前登录用户ID
     * @return 处理结果，true为成功
     * @throws DatabaseOperationException 数据库操作异常
     */
    @Override
    @Transactional
    public boolean removeTeaching(Long termId, Long bookId, Long teacherId, Long currUserId) throws DatabaseOperationException{
        LambdaQueryWrapper<Teaching> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Teaching::getTeacherId, teacherId);
        queryWrapper.eq(Teaching::getBookId, bookId);
        queryWrapper.eq(Teaching::getTermId, termId);
        List<Teaching> teachingList = this.list(queryWrapper);
        if (CollectionUtils.isEmpty(teachingList)) {
            return false;
        }
        // 更新更新用户ID
        boolean updated = this.updateBatchById(teachingList.stream().peek(teaching -> teaching.setUpdateUser(currUserId)).collect(Collectors.toList()));
        // 删除记录
        boolean delete = this.removeByIds(teachingList.stream().map(Teaching::getId).collect(Collectors.toList()));
        if (!updated || !delete){
            throw new DatabaseOperationException("数据库操作失败");
        }
        return true;
    }

    /**
     * 获取教学计划并封装到指定格式结果集
     * @param termId 学期ID
     * @param bookId 课程ID，可选
     * @param teacherId 教师ID，可选
     * @param clazzId 班级ID，可选
     * @return 教学计划并封装到指定格式结果集
     */
    @Override
    public List<TeachingListResult> getTeachingByFormat(Long termId, Long bookId, Long teacherId, Long clazzId){
        // 构造结果集
        List<TeachingListResult> results = new ArrayList<>();
        // 构造查询条件
        LambdaQueryWrapper<Teaching> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Teaching::getTermId, termId);
        queryWrapper.eq(bookId != null, Teaching::getBookId, bookId);
        queryWrapper.eq(teacherId != null, Teaching::getTeacherId, teacherId);
        List<Teaching> teachingList = this.list(queryWrapper);
        // 如果班级ID不为空，则过滤班级
        if (clazzId != null){
            List<Long> clazzIds = teachingList.stream().map(Teaching::getClazzId).collect(Collectors.toList());
            // 找出教学计划记录里包含所检索班级的记录
            teachingList = teachingList.stream().filter(teaching -> clazzIds.contains(clazzId)).collect(Collectors.toList());
        }

        // 准备数据
        Term term = termService.getById(termId);// 学期
        List<Book> courses = bookService.getBookList().stream().filter(book -> book.getType().equals(COURSE_TYPE)).collect(Collectors.toList());
        List<Clazz> clazzList = clazzService.list();
        List<Leader> leaders = leaderService.list();
        // 去重，找出教师ID去重列表
        List<Long> teacherIds = teachingList.stream().map(Teaching::getTeacherId).distinct().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(teacherIds)) {
            return results;
        }
        List<Teacher> teachers = teacherService.listByIds(teacherIds);// 准备教师信息

        for (Teacher teacher : teachers) {
            TeachingListResult listResult = new TeachingListResult();
            listResult.setTeacherId(teacher.getId());
            listResult.setTeacherName(teacher.getName());
            listResult.setTermId(term.getId());
            listResult.setTermName(term.getName());
            // 过滤出当前教师所教授的课程ID
            List<Long> courseIds = teachingList.stream().filter(teaching -> teaching.getTeacherId().equals(teacher.getId())).map(Teaching::getBookId).collect(Collectors.toList());
            // 构造次级列表
            List<TeachingSubListResult> subListResults = new ArrayList<>();
            for (Book course : courses.stream().filter(course -> courseIds.contains(course.getId())).collect(Collectors.toList())) {
                TeachingSubListResult subListResult = new TeachingSubListResult();
                subListResult.setCourseId(course.getId());
                subListResult.setCourseName(course.getName());
                // 判断是否是课程组组长
                Optional<Leader> optional = leaders.stream().filter(leader -> leader.getTeacherId().equals(teacher.getId()) && leader.getBookId().equals(course.getId()) && leader.getTermId().equals(termId))
                        .findFirst();
                subListResult.setPosition(optional.isPresent() ? 1 : 0);// 1表示是课程组组长
                // 过滤班级ID列表
                List<Long> clazzIds = teachingList.stream().filter(teaching -> teaching.getTeacherId().equals(teacher.getId()) && teaching.getBookId().equals(course.getId()))
                        .map(Teaching::getClazzId).collect(Collectors.toList());
                // 查找班级ID列表的班级信息，并且转换为结果封装类
                subListResult.setClazzs(clazzList.stream().filter(clazz -> clazzIds.contains(clazz.getId())).map(clazz -> {
                    ClazzListResult clazzListResult = new ClazzListResult();
                    BeanUtils.copyProperties(clazz, clazzListResult);
                    return clazzListResult;
                }).collect(Collectors.toList()));
                subListResults.add(subListResult);
            }
            listResult.setTeachingList(subListResults);// 将刺激列表添加
            results.add(listResult);// 将结果添加到结果集
        }
        return results;
    }
}
